home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / ODF Release 3 / ODFDev / ODF / Found / FWExcLib / FWExcImp.h < prev    next >
Encoding:
Text File  |  1996-12-16  |  10.3 KB  |  271 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWExcImp.h
  4. //    Release Version:    $ ODF 3 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. //========================================================================================
  11. //    THEORY OF OPERATION
  12. //
  13. //    This subsystem provides an emulation for C++ exception handling for compilers that
  14. //    do not yet support exceptions.
  15. //
  16. //    When an exception is thrown, the stack is unwound to the first enclosing try/catch 
  17. //    block.  Automatic (stack) objects are destroyed during stack unwinding.  Exceptions
  18. //    thrown during the construction of either an automatic or a dynamic (heap) object will
  19. //    result in the fully constructed subobjects of the partially constructed object
  20. //    being destroyed.
  21. //
  22. //    To obtain this behavior with exception handling emulation, the programmer must do
  23. //    extra work:
  24. //
  25. //        1) Classes which are to be destroyed during unwinding must be "registered"
  26. //        as auto-destruct classes, using the FW_DECLARE_AUTO and FW_DEFINE_AUTO
  27. //        macros 
  28. //
  29. //        2) The destructor and every constructor of auto-destruct classes must invoke 
  30. //        the FW_START_DESTRUCTOR and FW_END_CONSTRUCTOR macros (respectively).
  31. //
  32. //        3) Auto-destruct objects allocated on the heap must be allocated using the
  33. //        FW_NEW macro instead of using a plain new expression.
  34. //
  35. //    For the emulation to work, the code executed by the FW_END_CONSTRUCTOR and
  36. //    FW_START_DESTRUCTOR macros must determine the storage class of the object being
  37. //    constructed/destructed.  There are three possibilities: 1) automatic, 2) static, and
  38. //    3) dynamic.
  39.  
  40. //    Automatic objects must be tracked by the exception emulation.  
  41. //    Determining if the address of an object is on the stack is platform dependent but
  42. //    generally easy to do. We currently assume that it is possible to obtain a value
  43. //    for the stack base when the exception system in initialized, and store this value
  44. //    in the exception globals.  Care must be taken in a threaded environment with
  45. //    multiple stacks.  The stack top is determined by simply calling a function that
  46. //    returns the address of a local variable.
  47. //
  48. //    Static objects need not be tracked by the exception emulation, so
  49. //    the FW_END_CONSTRUCTOR and FW_START_DESTRUCTOR macros should act as no-ops.
  50. //    Unfortunately, there is no easy/portable way to determine if an address is located
  51. //    in the static data area.  We attempt to determine if the object is in static data
  52. //    via the process of elimination.  If the object is neither automatic or dynamic, then
  53. //    it is presumed to be static.  Unfortunately, this process of elimination gives incorrect
  54. //    results when programmer makes a particular mistake.  The mistake is relatively easy to
  55. //  make, and cannot be detected at compile time.  The mistake is made when a programmer
  56. //    creates a class that is not declared to be auto-destruct, but embeds an auto-destruct
  57. //    member object (by value) in the class.  When such a class is allocated in the heap
  58. //    via a new expression.
  59. //
  60. //    Dynamic auto-destruct objects must be allocated via the FW_NEW macro.  The FW_NEW
  61. //    macro invokes a special overloaded variant of operator new, and this variant registers
  62. //    the address range of the object being dynamically constructed.  This makes it
  63. //    relatively easy to determine if an address is that of an object (or subobject)
  64. //    currently being dynamically constructed.
  65. //
  66. //    There are several weaknesses with this mechanism for determining the storage class
  67. //    of an object.
  68. //
  69. //    First, if a class has member objects that are autodestruct objects,
  70. //    but the class itself is not autodestruct, then if it is allocated dynamically the
  71. //    member objects will not appear to be dynamic objects.  They are correctly rejected
  72. //    as automatic objects, so they are incorrectly classified as static objects, and the
  73. //    emulation incorrectly decides they need not be tracked.  The debug version of the
  74. //    emulation detects this problem and issues a warning.  Unfortunately, the warning
  75. //    might be issued for bonafide static objects, described next.
  76. //
  77. //    Second, any object which is not within a try-block context is assumed to be static.
  78. //    This assumption will always be valid in an application that does not dynamically
  79. //    load shared libraries at runtime.  (Not true! What about compilers/runtimes that
  80. //    delay construction of static objects until the first function call in a translation
  81. //    unit?)
  82. //
  83. //========================================================================================
  84.  
  85. #ifndef FWEXCIMP_H
  86. #define FWEXCIMP_H
  87.  
  88. #ifndef FWENVDEF_H
  89. #include "FWEnvDef.h"
  90. #endif
  91.  
  92. #ifndef SLPRIMEM_H
  93. #include "SLPriMem.h"
  94. #endif
  95.  
  96. #ifndef FWCLAIMP_H
  97. #include "FWClaImp.h"
  98. #endif
  99.  
  100. #include <setjmp.h>
  101.  
  102. #if defined(FW_BUILD_MAC) && !defined(__TYPES__)
  103. #include <Types.h>
  104. #endif
  105.  
  106. #if defined(FW_BUILD_MAC) && !defined(__THREADS__)
  107. #include <Threads.h>
  108. #endif
  109.  
  110. //========================================================================================
  111. // Forward Declarations
  112. //========================================================================================
  113.  
  114. FW_EXTERN_C_BEGIN
  115.  
  116. struct FW_SPrivTryBlockContext;
  117. struct FW_SPrivWatcher;
  118. struct FW_SPrivDeleteElem;
  119. struct FW_SPrivExceptionInfo;
  120.  
  121. typedef void (*FW_PrivDestroyProc)(void* self);
  122. typedef void (*FW_PrivDeleteProc)(void* self);
  123. typedef void (*FW_PrivCloneProc)(void* source, void* destination, size_t destSize);
  124. typedef void (*FW_PrivLongJumpProc)(jmp_buf,int);
  125.  
  126. #ifdef FW_DEBUG
  127.     void FW_AutoConstructed(void* object, size_t size, FW_PrivDestroyProc destroyer, char* name);
  128.     void FW_AutoDestructed(void* object, FW_PrivDestroyProc destroyer, char* name);
  129. #else
  130.     void FW_AutoConstructed(void* object, size_t size, FW_PrivDestroyProc destroyer);
  131.     void FW_AutoDestructed(void* object);
  132. #endif
  133.  
  134. void FW_PrivCaughtException(void* exception, size_t size, FW_SClassInfoPtr itsClass, FW_PrivDestroyProc itsDestroyer, FW_PrivCloneProc itsCloner);
  135. void FW_PrivCaughtReferenceException();
  136. void FW_PrivCaughtNoInstanceException();
  137. void FW_PrivCaughtEverythingException();
  138. void FW_PrivKeepThrowing();
  139. void FW_PrivCatchCleanup();
  140. void FW_PrivThrow(void* exception, size_t size, FW_SClassInfoPtr itsClass, FW_PrivDestroyProc itsDestroyer, FW_PrivCloneProc itsCloner);
  141. void FW_PrivThrowSame();
  142.  
  143. FW_Boolean FW_PrivCanCatchThisException(FW_SClassInfoPtr targetClass);
  144.  
  145. void FW_PrivTryBlockContext_Init(FW_SPrivTryBlockContext *self, jmp_buf buffer, FW_PrivLongJumpProc jumpProc);
  146. void FW_PrivTryBlockContext_Destroy(void *self);
  147. FW_SPrivTryBlockContext* FW_PrivTryBlockContext_MakeCurrent(FW_SPrivTryBlockContext* context);
  148.  
  149. void FW_PrivWatcher_Init(FW_SPrivWatcher* self, FW_PrivDeleteProc deleter);
  150. void* FW_PrivWatcher_Pop();
  151. void FW_PrivWatcher_Destroy(void* self);
  152. void* FW_PrivWatcher_New(void*p, size_t size, FW_SPrivWatcher* self);
  153.  
  154. void* FW_PrivGetThrownException();
  155.  
  156. #ifdef FW_BUILD_MAC
  157.  
  158. typedef ThreadID         FW_PlatformThreadID;
  159.  
  160. #else
  161.  
  162. typedef unsigned long     FW_PlatformThreadID;
  163.  
  164. #endif
  165.  
  166. //========================================================================================
  167. // volatile kludge
  168. //========================================================================================
  169.  
  170. // The FW_VOLATILE macro is used to workaround a problem that can happen with
  171. // setjmp/longjmp when variables are placed in registers. The macro takes the address
  172. // of the variable in an attempt to convince the compiler to not place the variable in
  173. // a register.  However, the result is not used, the compiler is free to eliminate the
  174. // expression, and then notice that the variable can be placed in register after all.
  175. // So, we take the address and place the result in this global.
  176.  
  177. extern void* FW_gPrivVolatileKludge;
  178.  
  179. //========================================================================================
  180. // struct FW_SPrivExceptionInfo
  181. //========================================================================================
  182.  
  183. struct FW_SPrivExceptionInfo
  184. {
  185.     void*                     fAddress;
  186.     size_t                    fSize;
  187.     FW_SClassInfoPtr        fClass;
  188.     FW_PrivDestroyProc         fDestroyer;
  189.     FW_PrivCloneProc         fCloner;
  190. };
  191.  
  192. //========================================================================================
  193. // struct FW_SPrivDeleteElem
  194. //========================================================================================
  195.  
  196. struct FW_SPrivDeleteElem
  197. {
  198.     void*                 fObject;
  199.     FW_PrivDestroyProc     fDestroyer;
  200. #ifdef FW_DEBUG
  201.     char*                fName;
  202.     FW_Boolean            fHeapAllocated;
  203. #endif
  204. };
  205.  
  206. //========================================================================================
  207. // struct FW_SPrivWatcher
  208. //========================================================================================
  209.  
  210. struct FW_SPrivWatcher
  211. {
  212.     FW_SPrivWatcher*    fNext;
  213.     void*                fObject;
  214.     void*                fLimit;
  215.     FW_PrivDeleteProc    fDeleter;
  216. #ifdef FW_DEBUG
  217.     long                fDeleteElems;
  218. #endif
  219. };
  220.  
  221. //========================================================================================
  222. // struct FW_SPrivTryBlockContext
  223. //========================================================================================
  224.  
  225. struct FW_SPrivTryBlockContext
  226. {
  227.     FW_SPrivTryBlockContext*    fPriorContext;
  228.     long                         fDeleteStackLevel;
  229.     jmp_buf*                    fJumpBuffer;
  230.     FW_PrivLongJumpProc            fJumpProc;
  231.     void*                        fPriorStackBase;
  232.     void*                        fPriorProcessBase;
  233.     FW_PlatformThreadID            fPriorThreadID;
  234. };
  235.  
  236.  
  237. //========================================================================================
  238. // Design Notes
  239. //========================================================================================
  240.  
  241. /*
  242.  
  243. At construction time:
  244.     If stack or current heap object, Push DeleteElem on stack
  245.  
  246. At end of FW_NEW
  247.     Walk DeleteStack, removing entries for this object
  248.  
  249. At destruction time:
  250.     if the object is a stack based object, remove entry from DeleteStack
  251.  
  252. At stack-unwind time
  253.     Delete each elem on delete stack
  254.  
  255. At end of try-block scope
  256.     Verify delete stack is back to initial state
  257.  
  258. Note: the above approach assumes a try-way distinction for storage class of objects.
  259. Objects may be curent-heap, stack, or other.  Current-heap objects are objects currently
  260. being allocated via FW_NEW.  There is effectively a stack of such objects, in case
  261. the constructor of an object being allocated with FW_NEW calls FW_NEW to allocate
  262. another object.  The current-heap object is the top element of this stack.  The other
  263. category thus includes static objects and heap based objects other than the current-heap
  264. object.
  265.  
  266. */
  267.  
  268. FW_EXTERN_C_END
  269.  
  270. #endif
  271.